package com.warski.wonderfires.net;

import android.util.Log;

import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import com.warski.wonderfires.TheApplication;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * Created by Administrator on 2018/12/4.
 */

public class UdpSend {
    private UdpSend() { }
    private static UdpSend _instance = null;
    public static UdpSend getInstance() {
        if(_instance == null)
            _instance = new UdpSend();
        return _instance;
    }

    private static final String Tag = "UdpSend";
    private final int BROADCASTPORT = 7002; //广播的发送端口
    private final int EachWaitTime = 300; //每个联网步骤的等待时长0-发送局域网广播获取地址 1-连接局域网TCP 2-连接内网IP 3-连接麦驰云
    Gson gson = new Gson();
    private DatagramSocket BrocastRcvSocket;
    private ICallbackNetConn callback = null;
    public void setNetCallback(ICallbackNetConn callback) {
        this.callback = callback;
    }
    public void sendBrocast() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                sendData(true);//尝试发送UDP广播 等待室内机返回可用的IP和端口
            }
        }).start();
    }
    void sendData(boolean isInThread) {
        if(callback != null)
            callback.startConnStep(ConnStep.BroadcastLocal);
        try {
            BrocastRcvSocket = new DatagramSocket(BROADCASTPORT);// 创建用来发送数据报包的套接字
            String str = "{\"type\":\"REQUEST_TCP\",\"sn\":\"123456\"}";
            DatagramPacket dp = new DatagramPacket(str.getBytes(),
                    str.getBytes().length,
                    InetAddress.getByName("255.255.255.255"), 7007); //6666
            BrocastRcvSocket.setReceiveBufferSize(150);
            CmdWorker worker = new CmdWorker();
            worker.start();
            Log.i(Tag, "尝试发送局域网广播,等待地址应答");
            // 构造数据报包，用来将长度为 length 的包发送到指定主机上的指定端口号
            try {
                BrocastRcvSocket.send(dp);
                Thread.sleep(EachWaitTime);
            } catch (Exception e) {
                e.printStackTrace();
            }
            //设置1秒钟内join掉的能力 使能局域网广播无设备时 能快速切换到内网IP的检测
            boolean bRst = false;
            try {
                if(!worker.exit)
                    worker.join(1000);
                bRst = worker.exit;
            } catch (Exception ex) {
                worker.interrupt();
            }

            if (bRst) connOneStep();

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    void connOneStep() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                if(callback != null)
                    callback.startConnStep(ConnStep.ConnectingLocal);
                boolean bRet = TCPConn.getInstance().tryNetAddr(TheApplication.localGateIP, TheApplication.localGatePort, EachWaitTime);
                if(bRet && callback != null)
                    callback.connSucceed(ConnStep.ConnectingLocal, TheApplication.localGateIP, bRet, true, true);

            }
        }).start();
    }

    public void callDealStep(ConnStep step) {
        if(callback != null)
            callback.startConnStep(step);
    }

    private class CmdWorker extends Thread {
        private boolean exit = false;
        private byte[] buf = new byte[150];
        @Override
        public void run() {
            try {
                Log.i(Tag, "广播接收线程已启动，等待接收反馈");
                DatagramPacket RecDataPacket = new DatagramPacket(buf, buf.length);
                BrocastRcvSocket.receive(RecDataPacket);
                byte[] Buffer = RecDataPacket.getData();
                String recvData = (new String(Buffer, 0, Buffer.length, "utf-8")).trim();
                // 解析JSON
                Auth auth = gson.fromJson(recvData, Auth.class);
                if (auth != null) {
                    exit = true;
                    TheApplication.localGatePort = auth.port;
                    TheApplication.localGateIP = auth.ip;
                    Log.i(Tag, String.format(" 局域网广播获取室内机IP:%s 端口:%s", auth.ip, auth.port));
                }
                Log.i(Tag, " data recvData:" + recvData);
                BrocastRcvSocket.close();
            } catch (Exception ex) {
                exit = false;
                Log.i(Tag, " 广播接收出现异常 ！");
                BrocastRcvSocket.close();
                ex.printStackTrace();
            }
            exit = true;
        }
    }

    class Auth {
        public String ip; // 服务端IP地址
        public short port; // 服务端端口
    }
}
